/*
 * Copyright 2020-2021 redragon.dongbin
 *
 * This file is part of redragon-erp/赤龙ERP.

 * redragon-erp/赤龙ERP is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.

 * redragon-erp/赤龙ERP is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with redragon-erp/赤龙ERP.  If not, see <https://www.gnu.org/licenses/>.
 */
package com.erp.inv.input.service.spring;

import com.erp.common.voucher.service.FinVoucherBillRService;
import com.erp.common.voucher.service.FinVoucherHeadService;
import com.erp.common.voucher.service.FinVoucherModelHeadService;
import com.erp.hr.base.util.CommonUtils;
import com.erp.hr.dao.model.HrStaffInfoRO;
import com.erp.hr.service.HrCommonService;
import com.erp.inv.input.dao.InvInputHeadDao;
import com.erp.inv.input.dao.InvInputLineDao;
import com.erp.inv.input.dao.model.*;
import com.erp.inv.input.service.InvInputHeadService;
import com.erp.inv.input.service.InvInputLineService;
import com.erp.inv.stock.dao.model.InvStock;
import com.erp.inv.stock.service.InvStockService;
import com.erp.masterdata.common.model.BaseModel;
import com.erp.masterdata.common.param.MasterDataParam;
import com.erp.order.dn.dao.model.DeliveryNoteHead;
import com.erp.order.dn.dao.model.DeliveryNoteLine;
import com.erp.order.dn.service.DeliveryNoteHeadService;
import com.erp.order.dn.service.DeliveryNoteLineService;
import com.erp.order.po.dao.model.PoHead;
import com.erp.order.po.dao.model.PoLine;
import com.erp.order.po.service.PoHeadService;
import com.erp.order.po.service.PoLineService;
import com.erp.order.supply.model.*;
import com.erp.order.supply.service.SupplyMaterialDetailService;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.fop.area.Page;
import org.redragon.framework.hibernate.data.SnowFlake;
import org.redragon.framework.hibernate.model.Pages;
import org.redragon.framework.util.ShiroUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Service
@Transactional(rollbackFor=Exception.class)
public class InvInputHeadServiceImpl implements InvInputHeadService {

    //注入Dao
    @Autowired
    private InvInputHeadDao invInputHeadDao;
    @Autowired
    private InvInputLineService invInputLineService;
    @Autowired
    private InvStockService invStockService;
    @Autowired
    private HrCommonService hrCommonService;
    @Autowired
    @Qualifier("finVoucherModelHeadServiceCommon")
    private FinVoucherModelHeadService finVoucherModelHeadService;
    @Autowired
    @Qualifier("finVoucherHeadServiceCommon")
    private FinVoucherHeadService finVoucherHeadService;
    @Autowired
    @Qualifier("finVoucherBillRServiceCommon")
    private FinVoucherBillRService finVoucherBillRService;
    @Autowired
    private PoLineService poLineService;
    @Autowired
    private PoHeadService poHeadService;
    @Autowired
    private InvInputLineDao invInputLineDao;
    @Autowired
    private DeliveryNoteHeadService deliveryNoteHeadService;
    @Autowired
    private DeliveryNoteLineService deliveryNoteLineServic;
    @Autowired
    private SupplyMaterialDetailService supplyMaterialDetailService;

    
    @Override
    public void insertDataObject(InvInputHead obj) {
        this.invInputHeadDao.insertDataObject(obj);
    }

    @Override
    public void updateDataObject(InvInputHead obj) {
        this.invInputHeadDao.updateDataObject(obj);
    }
    
    @Override
    public void insertOrUpdateDataObject(InvInputHead obj) {
        this.invInputHeadDao.insertOrUpdateDataObject(obj);
    }

    @Override
    public void deleteDataObject(InvInputHead obj) {
        //逻辑删除主表数据
        obj.setIsDel(MasterDataParam.IS_DEL_YES);
        invInputHeadDao.insertOrUpdateDataObject(obj);
        //this.invInputHeadDao.deleteDataObject(obj);
        //逻辑删除明细表
        this.invInputLineService.deleteInvInputLineByInputHeadCode(obj.getInputHeadCode());
    }

    @Override
    public List<InvInputHead> getDataObjects() {
        return this.invInputHeadDao.getDataObjects();
    }

    @Override
    public InvInputHead getDataObject(int id) {
        return this.invInputHeadDao.getDataObject(id);
    }

    @Override
    public InvInputHead getDataObject(String code) {
        return this.invInputHeadDao.getDataObject(code);
    }

    @Override
    public List<InvInputHead> getDataObjects(InvInputHeadCO paramObj) {
        return this.invInputHeadDao.getDataObjects(paramObj);
    }

    @Override
    public List<InvInputHead> getDataObjects(Pages pages) {
        return this.invInputHeadDao.getDataObjects(pages);
    }
    
    @Override
    public List<InvInputHead> getDataObjects(Pages pages, InvInputHeadCO paramObj) {
        return this.invInputHeadDao.getDataObjects(pages, paramObj);
    }
    
    @Override
    public List<Map<String, Object>> getDataObjectsArray(Pages pages, InvInputHeadCO paramObj) {
        return this.invInputHeadDao.getDataObjectsArray(pages, paramObj);
    }
    
    @Override
    public List<InvInputHead> getDataObjectsForDataAuth(String dataAuthSQL, Pages pages, InvInputHeadCO paramObj) {
        return this.invInputHeadDao.getDataObjectsForDataAuth(dataAuthSQL, pages, paramObj);
    }
    
    @Override
    public void updateApproveStatus(String code, String approveStatus) {
        InvInputHead invInputHead = invInputHeadDao.getDataByCode(code);
        if(MasterDataParam.INPUT_TYPE_RETURN.equals(invInputHead.getInputType()) && MasterDataParam.APPROVE_STATUS_SUBMIT.equals(approveStatus) ){
            approveStatus = MasterDataParam.APPROVE_STATUS_APPROVE;
            //找到管理的发货单然后再找到发货单关联的订单
            DeliveryNoteHead deliveryNoteHead = deliveryNoteHeadService.getDataObjectByCode(invInputHead.getInputSourceHeadCode());
            PoHead poHead = poHeadService.getDataObject(deliveryNoteHead.getPoId());
            //再采购单例生成一个退货数据里生成一个
            PoHead newPoHead = new PoHead();
            BeanUtils.copyProperties(poHead, newPoHead);
            RemoveFixedFields(newPoHead);
            newPoHead.setPoHeadId(null);
            newPoHead.setPoHeadCode(MasterDataParam.INPUT_TYPE_RETURN + DateFormatUtils.format(new Date(), "yyyyMMdd") + poHeadService.getHeadCodeNo());
            newPoHead.setPoType(MasterDataParam.INPUT_TYPE_RETURN);
            newPoHead.setPoName(poHead.getPoName() +"("+ MasterDataParam.RETURN_NAME +")");
            newPoHead.setPoDesc(invInputHead.getMemo());
            newPoHead.setStatus(MasterDataParam.STATUS_NEW);
            newPoHead.setApproveStatus(MasterDataParam.APPROVE_STATUS_SUBMIT);
            newPoHead.setReceiveStatus(MasterDataParam.MATERIAL_STATUS_N);
            newPoHead.setPaymentStatus(MasterDataParam.MATERIAL_STATUS_N);
            newPoHead.setIsDel(MasterDataParam.IS_DEL_NO);
            poHeadService.insertDataObject(newPoHead);
            //新增订单子表数据
            List<InvInputLine> invInputLines = invInputLineService.getInvInputLineListByInputHeadCode(invInputHead.getInputHeadCode());
            for(InvInputLine inputLine : invInputLines){
                PoLine poLine = new PoLine();
                poLine.setPoLineCode(SnowFlake.getConcurrentId().toString());
                poLine.setPoHeadCode(newPoHead.getPoHeadCode());
                poLine.setMaterialCode(inputLine.getMaterialCode());
                poLine.setQuantity(inputLine.getQuantity());
                poLine.setPrice(inputLine.getPrice());
                poLine.setAmount(inputLine.getQuantity().multiply(inputLine.getPrice()));
                poLine.setUnit(inputLine.getUnit());
                poLine.setStatus(MasterDataParam.MATERIAL_STATUS_Y);
                poLine.setIsDel(MasterDataParam.IS_DEL_NO);
                poLineService.insertDataObject(poLine);
            }
        }else if(MasterDataParam.INPUT_TYPE_SWAP.equals(invInputHead.getInputType()) && MasterDataParam.APPROVE_STATUS_SUBMIT.equals(approveStatus) ){
            approveStatus = MasterDataParam.APPROVE_STATUS_APPROVE;
            //找到管理的发货单
            DeliveryNoteHead deliveryNoteHead = deliveryNoteHeadService.getDataObjectByCode(invInputHead.getInputSourceHeadCode());
            //生成一个新的发货单
            DeliveryNoteHead newNoteHead = new DeliveryNoteHead();
            BeanUtils.copyProperties(deliveryNoteHead, newNoteHead);
            RemoveFixedFields(newNoteHead);
            newNoteHead.setId(null);
            newNoteHead.setDeliveryCode(MasterDataParam.INPUT_TYPE_SWAP + DateFormatUtils.format(new Date(), "yyyyMMdd") + deliveryNoteHeadService.getNewDeliveryCode());
            newNoteHead.setDeliveryName(deliveryNoteHead.getDeliveryName() + "(" + MasterDataParam.SWAP_NAME + ")");
            newNoteHead.setIsDel(MasterDataParam.IS_DEL_NO);
            deliveryNoteHeadService.insertDataObject(newNoteHead);
            List<InvInputLine> invInputLines = invInputLineService.getInvInputLineListByInputHeadCode(invInputHead.getInputHeadCode());
            for(InvInputLine line : invInputLines){
                DeliveryNoteLine oldLine = deliveryNoteLineServic.getDataObject(Integer.valueOf(line.getInputSourceLineCode()));
                DeliveryNoteLine noteLine = new DeliveryNoteLine();
                noteLine.setDeliveryId(newNoteHead.getId());
                noteLine.setDeliveryCode(newNoteHead.getDeliveryCode());
                noteLine.setMaterialCode(line.getMaterialCode());
                noteLine.setMaterialName(oldLine.getMaterialName());
                noteLine.setStandard(oldLine.getStandard());
                noteLine.setPurchasedAmount(line.getQuantity());
                noteLine.setStandardUnit(line.getUnit());
                noteLine.setUnitPrice(line.getPrice());
                noteLine.setSum(line.getPrice().multiply(line.getPrice()));
                noteLine.setTaxRate(oldLine.getTaxRate());
                noteLine.setDeliveryDate(new Date());
                noteLine.setStatus(MasterDataParam.MATERIAL_STATUS_N);
                noteLine.setIsDel(MasterDataParam.IS_DEL_NO);
                deliveryNoteLineServic.insertDataObject(noteLine);
            }

        }
        this.invInputHeadDao.updateApproveStatus(code, approveStatus);
        
        //获取头
        InvInputHead head = this.invInputHeadDao.getDataObject(code);
        //入库审批通过后修改入库成功后的关联数据
        if(approveStatus.equals("APPROVE")) {
            //===========================修改库存明细
            
            //获取行
            Pages pages = new Pages();
            pages.setPage(1);
            pages.setMax(1000);
            InvInputLineCO invInputLineCO = new InvInputLineCO();
            invInputLineCO.setInputHeadCode(code);
            List<InvInputLine> lineList = this.invInputLineService.getInvInputLineListByInputHeadCode(pages, invInputLineCO);
            
            //先删除之前的保留和占用
            this.invStockService.deleteInvStockByBillHeadCode("INPUT%", code);
            
            //循环插入库存
            for(InvInputLine line: lineList) {
                InvStock stock = new InvStock();
                stock.setBillHeadCode(head.getInputHeadCode());
                stock.setBillLineCode(line.getInputLineCode());
                stock.setMaterialCode(line.getMaterialCode());
                stock.setStockCode(SnowFlake.getConcurrentId().toString());
                stock.setWarehouseCode(head.getWarehouseCode());
                if(head.getInputType().equals("PO_RETURN")) {
                    stock.setBillType("INPUT_RETURN");
                    stock.setMemo("入库退货单自动创建");
                    stock.setStockNumber(line.getInputQuantity().multiply(new BigDecimal(-1)));
                }else if(head.getInputType().equals("OTHER_IN")){
                    stock.setBillType("INPUT_OTHER");
                    stock.setMemo("杂项入库单自动创建");
                    stock.setStockNumber(line.getInputQuantity());
                }else if(head.getInputType().equals("PROD_RETURN")){
                    stock.setBillType("INPUT_PROD_RETURN");
                    stock.setMemo("生产退料单自动创建");
                    stock.setStockNumber(line.getInputQuantity());
                }else if(head.getInputType().equals("WIP_IN")){
                    stock.setBillType("INPUT_PROD");
                    stock.setMemo("工厂入库单自动创建");
                    stock.setStockNumber(line.getInputQuantity());
                }else {
                    stock.setBillType("INPUT");
                    stock.setMemo("入库单自动创建");
                    stock.setStockNumber(line.getInputQuantity());
                }
                //获取当前用户职员信息
                HrStaffInfoRO staffInfo = this.hrCommonService.getStaffInfo(ShiroUtil.getPrincipal());
                stock.setStaffCode(staffInfo.getStaffCode());
                stock.setDepartmentCode(staffInfo.getDepartmentCode());
                
                this.invStockService.insertDataObject(stock);
            }
            
            //===========================自动生成凭证和分录
            //计算分录的金额
            //获取入库行
            List<InvInputLine> inputLineList = this.invInputLineService.getInvInputLineListByInputHeadCode(code);
            
            BigDecimal voucherAmount = new BigDecimal(0D);
            //循环获取加和入库数量和物料单价
            for(InvInputLine invInputLine: inputLineList) {
                //如果杂项入库则直接取金额，否则从订单计算金额
                if(invInputLine.getAmount()==null) {
                    BigDecimal quantity = invInputLine.getInputQuantity();
                    //获取采购订单行
                    PoLine poLine = this.poLineService.getDataObject(invInputLine.getInputSourceLineCode());
                    BigDecimal price = poLine.getPrice();
                    //计算行金额
                    BigDecimal lineAmount = quantity.multiply(price);
                    //计算合计金额
                    voucherAmount = voucherAmount.add(lineAmount);
                }else {
                    //计算合计金额
                    voucherAmount = voucherAmount.add(invInputLine.getAmount());
                }
                
            }
            
            //调用自动创建方法
            String billType = com.erp.common.voucher.dao.data.DataBox.getVoucherTypeByBusinessType(head.getInputType());
            this.finVoucherModelHeadService.autoCreateVoucher(code, new Double[]{voucherAmount.doubleValue()}, billType);
        }else if(approveStatus.equals("UNSUBMIT")) {
            //更新行表版本号
            this.invInputLineDao.updateLineForVersion(code);
            
            //===========================//删除入库库存
            if(head.getInputType().equals("PO_RETURN")) {
                this.invStockService.deleteInvStockByBillHeadCode("INPUT_RETURN", code);
            }else if(head.getInputType().equals("OTHER_IN")){
                this.invStockService.deleteInvStockByBillHeadCode("INPUT_OTHER", code);
            }else if(head.getInputType().equals("PROD_RETURN")){
                this.invStockService.deleteInvStockByBillHeadCode("INPUT_PROD_RETURN", code);
            }else if(head.getInputType().equals("WIP_IN")){
                this.invStockService.deleteInvStockByBillHeadCode("INPUT_PROD", code);
            }else {
                this.invStockService.deleteInvStockByBillHeadCode("INPUT", code);
            }
            
            
            //===========================删除自动生成的凭证和分录
            //根据单据头code获取凭证头code
            String billType = com.erp.common.voucher.dao.data.DataBox.getVoucherTypeByBusinessType(head.getInputType());
            String voucherHeadCode = this.finVoucherBillRService.getVoucherHeadCodeByBillHeadCode(billType, code);
            //删除凭证
            if(StringUtils.isNotBlank(voucherHeadCode)) {
                this.finVoucherHeadService.deleteFinVoucherHeadByVoucherHeadCode(voucherHeadCode);
            }
        }
    }

    @Override
    public InvInputHead getDataByCode(String inputHeadCode) {
        return invInputHeadDao.getDataByCode(inputHeadCode);
    }

    public <T extends BaseModel>T RemoveFixedFields (T t){
        t.setIsDel(null);
        t.setCreatedDate(null);
        t.setCreatedBy(null);
        t.setLastUpdatedDate(null);
        t.setLastUpdatedBy(null);
        t.setOrgCode(null);
        return t;
    }

    @Override
    public String getNewHeadCodeByType(String inputType) {
        Integer num = invInputHeadDao.getSumDataByType(inputType) + 1;
        String suffix = num.toString();
        StringBuilder result = new StringBuilder();
        for (int i = 0; i < CommonUtils.PURCHASING_REQUISITION_LENGRH - suffix.length(); i ++) {
            result.append("0");
        }
        result.append(suffix);
        return result.toString();
    }

    @Override
    public SupplyMaterialVO getSupplyMaterialByCode(String purchase_order_id) {
        return invInputHeadDao.getSupplyMaterialByCode(purchase_order_id);
    }

    @Override
     public List<SupplyMaterialBeanVo> getSupplyMaterial(Pages pages, SupplyMaterialBeanVo supplyMaterialBeanVo){
        return invInputHeadDao.getSupplyMaterial(pages,supplyMaterialBeanVo);
    }

    @Override
    public SupplyMaterialRVO getSupplyMaterialRByCode(String supplyMaterialId) {
        return invInputHeadDao.getSupplyMaterialRByCode(supplyMaterialId);
    }

    @Override
    public List<SupplyMaterialDetailVO> getSupplyMaterialDetailByCode(String supply_material_id) {
        return invInputHeadDao.getSupplyMaterialDetailByCode(supply_material_id);
    }

    @Override
    public SupplyMaterialDetailVO getMaterialDetailByCode(String id) {
        return invInputHeadDao.getMaterialDetailByCode(id);
    }

    @Override
    public SupplyMaterialDetailVO getSupplyMaterialDetailById(String id) {
        return invInputHeadDao.getSupplyMaterialDetailById(id);
    }

    @Override
    public void setSupplyMaterialDetailStatusByCode(SupplyMaterialDetail supplyMaterialDetail) {
        supplyMaterialDetailService.update(supplyMaterialDetail);
    }

    @Override
    public Integer getSupplyMaterialStatusCount(String supplyMaterialId) {
        return invInputHeadDao.getSupplyMaterialStatusCount(supplyMaterialId);
    }
}